﻿using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Waf.Applications;
using HighLandirect.Applications.Properties;
using HighLandirect.Applications.Services;
using HighLandirect.Applications.ViewModels;
using System;
using System.Waf.Applications.Services;
using System.IO;
using System.Linq;
using HighLandirect.Domain;
using System.Text;

namespace HighLandirect.Applications.Controllers
{
    [Export]
    public class ApplicationController : Controller
    {
        private readonly IQuestionService questionService;
        private readonly IFileDialogService fileDialogService;
        private readonly IMessageService messageService;
        private readonly IEntityController entityController;
        private readonly ProductController productController;
        private readonly ShellViewModel shellViewModel;
        private readonly DelegateCommand exitCommand;
        private readonly DelegateCommand getBackUpDataCommand;
        private readonly DelegateCommand setBackUpDataCommand;
        private readonly DelegateCommand getExportDataCommand;
        private readonly DelegateCommand setImportDataCommand;
        private readonly CustomerController customerController;
        private readonly OrderController orderController;

        private readonly IEntityService entityService;

        [ImportingConstructor]
        public ApplicationController(IQuestionService questionService, 
            IPresentationController presentationController, 
            IEntityController entityController, 
            CustomerController customerController, 
            ProductController productController,
            OrderController orderController,
            ShellViewModel shellViewModel, 
            IFileDialogService fileDialogService,
            IMessageService messageService, 
            IEntityService entityService)
        {
            if (presentationController == null) { throw new ArgumentNullException("presentationController"); }
            if (shellViewModel == null) { throw new ArgumentNullException("shellViewModel"); }
            
            presentationController.InitializeCultures();
            
            this.questionService = questionService;
            this.fileDialogService = fileDialogService;
            this.messageService = messageService;
            this.entityController = entityController;
            this.shellViewModel = shellViewModel;
            this.customerController = customerController;
            this.productController = productController;
            this.orderController = orderController;

            this.shellViewModel.Closing += ShellViewModelClosing;
            this.exitCommand = new DelegateCommand(Close);
            this.getBackUpDataCommand = new DelegateCommand(GetBackUpData);
            this.setBackUpDataCommand = new DelegateCommand(SetBackUpData);
            this.getExportDataCommand = new DelegateCommand(GetExportData);
            this.setImportDataCommand = new DelegateCommand(SetImportData);

            this.entityService = entityService;
        }


        public void Initialize()
        {
            this.shellViewModel.ExitCommand = this.exitCommand;
            this.shellViewModel.GetBackUpDataCommand = this.getBackUpDataCommand;
            this.shellViewModel.SetBackUpDataCommand = this.setBackUpDataCommand;
            this.shellViewModel.GetExportDataCommand = this.getExportDataCommand;
            this.shellViewModel.SetImportDataCommand = this.setImportDataCommand;

            entityController.Initialize();
            productController.Initialize();
            orderController.Initialize();

            //イマイチ・・・
            customerController.Initialize(orderController);
        }

        public void Run()
        {
            shellViewModel.Show();
        }

        public void Shutdown()
        {
            entityController.Shutdown();
        }

        private void ShellViewModelClosing(object sender, CancelEventArgs e)
        {
            if (entityController.HasChanges)
            {
                if (shellViewModel.IsValid)
                {
                    bool? result = questionService.ShowQuestion(Resources.SaveChangesQuestion);
                    if (result == true)
                    {
                        if (!entityController.Save())
                        {
                            e.Cancel = true;
                        }
                    }
                    else if (result == null)
                    {
                        e.Cancel = true;
                    }
                }
                else
                {
                    e.Cancel = !questionService.ShowYesNoQuestion(Resources.LoseChangesQuestion);
                }
            }
        }

        private void Close()
        {
            shellViewModel.Close();
        }

        private void GetBackUpData()
        {
            SaveIfYouWant();

            var result = this.fileDialogService.ShowSaveFileDialog(new FileType("SQL-Server Compact Database", ".sdf"));

            if (result.IsValid)
            {
                File.Copy(AppDomain.CurrentDomain.BaseDirectory + @"\Resources\MyData.sdf", result.FileName, true);
                this.messageService.ShowMessage("保存しました。");
            }
            else
            {
                this.messageService.ShowMessage("何かエラーです。保存に失敗しました。");
            }
        }

        private void SaveIfYouWant()
        {
            if (entityController.HasChanges)
            {
                if (shellViewModel.IsValid)
                {
                    var SaveQuestionResult = questionService.ShowQuestion("変更があります。処理の前にその変更を保存しますか？");
                    if (SaveQuestionResult == true)
                    {
                        this.entityController.Save();
                    }
                }
            }
        }

        private void SetBackUpData()
        {
            var result = this.fileDialogService.ShowOpenFileDialog(new FileType("SQL-Server Compact Database", ".sdf"));
            if (result.IsValid)
            {
                File.Copy(result.FileName, AppDomain.CurrentDomain.BaseDirectory + @"\Resources\MyData.sdf", true);
                this.messageService.ShowMessage("復元しました。再起動すると復元データを利用できます。");
            }
            else
            {
                this.messageService.ShowMessage("何かエラーです。保存に失敗しました。");
            }
        }

        private void GetExportData()
        {
            SaveIfYouWant();
            var result = this.fileDialogService.ShowSaveFileDialog(new FileType("顧客情報", ".txt"));

            if (result.IsValid)
            {
                using (var sw = new StreamWriter(result.FileName, false, Encoding.UTF8))
                {
                    sw.WriteLine(Customer.HeaderCsv);
                    foreach (var customer in this.entityService.Customers)
                        sw.WriteLine(Customer.GetCsvFromCustomer(customer));
                }
                this.messageService.ShowMessage("エクスポート完了。");
            }
            else
            {
                //this.messageService.ShowMessage("何かエラーです。エクスポートに失敗しました。");
            }
        }

        private void SetImportData()
        {
            var result = this.fileDialogService.ShowOpenFileDialog(new FileType("顧客情報", ".txt"));
            if (result.IsValid)
            {
                bool ExistsError = false;
                using (var sr = new StreamReader(result.FileName, Encoding.UTF8))
                using (var sw = new StreamWriter("ErrorList.txt", false, Encoding.UTF8))
                {
                    string Line = sr.ReadLine();
                    //ヘッダが設定されてたら読み捨てる
                    if (Line.Trim() == Customer.HeaderCsv)
                        Line = sr.ReadLine();
                    int i = 0;
                    while (Line != null)
                    {
                        i++;
                        if (Line.Trim().Length > 0)
                        {
                            try
                            {
                                int CustNo;
                                if (this.entityService.Customers.Count == 0)
                                {
                                    CustNo = 1;
                                }
                                else
                                {
                                    CustNo = this.entityService.Customers.OrderByDescending(x => x.CustNo).FirstOrDefault().CustNo;
                                }
                                var customer = Customer.GetCustomerFromCsv(Line, CustNo + 1);
                                this.entityService.Customers.Add(customer);
                            }
                            catch (Exception ex)
                            {
                                sw.WriteLine("{0}行目の{1}を設定中『{2}』のためエラーが発生しました。この行はインポートされません。",
                                            i.ToString(), ex.Source, ex.Message);
                                ExistsError = true;
                            }
                        }
                        Line = sr.ReadLine();
                    }
                }

                if (ExistsError)
                {
                    this.messageService.ShowMessage("インポートが完了しましたが、エラーが発生したためインポートできなかった行があります。\nOKをクリックすると詳細情報を表示します。");
                    System.Diagnostics.Process.Start("notepad.exe", "ErrorList.txt");
                }
                else
                {
                    this.messageService.ShowMessage("インポート完了。");
                }
                customerController.Initialize(orderController);
            }
            else
            {
                //his.messageService.ShowMessage("何かエラーです。インポートに失敗しました。");
            }
        }
    }
}
